package com.cctvcc.auth.service.impl;

import cn.cctvcc.core.constant.Constants;
import cn.cctvcc.core.constant.UserConstants;
import cn.cctvcc.core.constant.cache.CachePrefixConstants;
import cn.cctvcc.core.domain.R;
import cn.cctvcc.core.enums.common.CommonEnum;
import cn.cctvcc.core.enums.system.SysEmailSendTypeEnum;
import cn.cctvcc.core.utils.SecurityUtils;
import cn.cctvcc.core.utils.ServletUtils;
import cn.cctvcc.core.utils.StringUtil;
import cn.cctvcc.security.service.EmailTokenService;
import cn.cctvcc.security.service.KeysService;
import cn.cctvcc.security.service.SingleUseTokenService;
import cn.cctvcc.security.service.TokenService;
import cn.cctvcc.system.api.RemoteSysUserService;
import cn.cctvcc.system.api.domain.LoginUser;
import cn.cctvcc.system.api.domain.SysUser;
import com.cctvcc.auth.domain.LoginBody;
import com.cctvcc.auth.domain.RegisterBody;
import com.cctvcc.auth.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;
import java.util.Objects;

/**
 * @description: 鉴权实现类
 * @author: Jiang
 * @create: 2021-09-23 17:02
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private KeysService keysService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private EmailTokenService emailTokenService;
    @Autowired
    private RemoteSysUserService remoteSysUserService;
    @Autowired
    private SingleUseTokenService singleUseTokenService;

    /**
     * 登录
     */
    @Override
    public R<?> login(LoginBody loginBody) throws Exception {

        // 用户名或密码为空
        if (StringUtil.isAnyBlank(loginBody.getUsername(), loginBody.getPassword()))
            throw new RuntimeException("用户名与密码必须填写");
        // 用户名不在指定范围内
        if (loginBody.getUsername().length() < UserConstants.USERNAME_MIN_LENGTH || loginBody.getUsername().length() > UserConstants.USERNAME_MAX_LENGTH)
            throw new RuntimeException("用户名不在指定范围");

        LoginUser loginUser = getLoginUser(loginBody.getUsername());
        SysUser sysUser = loginUser.getSysUser();
        if (Objects.equals(CommonEnum.DELETED.getCode(), sysUser.getDelFlag()))
            throw new RuntimeException("对不起，您的账号" + loginBody.getUsername() + " 已被删除");
        if (Objects.equals(CommonEnum.DISABLE.getCode(), sysUser.getDelFlag()))
            throw new RuntimeException("对不起，您的账号" + loginBody.getUsername() + " 已被停用");
        if (!keysService.verifyPassword(loginBody.getPassword(), sysUser))
            throw new RuntimeException("用户名或密码错误");

        return R.ok(tokenService.createToken(loginUser), Constants.LOGIN_SUCCESS);
    }

    /**
     * 登出
     */
    @Override
    public R<?> logout() {

        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        if (!Objects.isNull(loginUser))
            tokenService.delLoginUser(loginUser.getToken());// 删除用户缓存记录
        return R.ok(null, Constants.LOGOUT);
    }

    /**
     * 注册
     */
    @Override
    public R<?> register(RegisterBody registerBody) {
        if (registerBody.getUsername().length() < UserConstants.USERNAME_MIN_LENGTH
                || registerBody.getUsername().length() > UserConstants.USERNAME_MAX_LENGTH)
            throw new RuntimeException("用户名不在指定范围");
        if (!emailTokenService.verifyKey(registerBody.getEmail(), registerBody.getCode()))
            throw new RuntimeException("邮件验证码错误");
        if (registerBody.getPassword().length() < UserConstants.PASSWORD_MIN_LENGTH
                || registerBody.getPassword().length() > UserConstants.PASSWORD_MAX_LENGTH)
            throw new RuntimeException("用户密码不在指定范围");
        if (StringUtil.isEmail(registerBody.getNickName()))
            throw new RuntimeException("昵称必需填写");
        SysUser sysUser = new SysUser();
        sysUser.setUserName(registerBody.getUsername());
        sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword()));
        sysUser.setEmail(registerBody.getEmail());
        sysUser.setNickName(registerBody.getNickName());
        return remoteSysUserService.add(sysUser, true);
    }

    /**
     * 忘记密码
     */
    @Override
    public R<?> forget(String emailValue, String code) {
        verifyUserName(emailValue);
        SysUser sysUser = getLoginUser(emailValue).getSysUser();
        emailValue = sysUser.getEmail();
        if (!emailTokenService.verifyKey(emailValue, code))
            throw new RuntimeException("邮件验证码错误");
        Cookie cookie = new Cookie(CachePrefixConstants.COOKIE_KEY, singleUseTokenService.createToken());
        cookie.setMaxAge(120);
        cookie.setPath("/");
        Cookie cookie2 = new Cookie(CachePrefixConstants.FORGET_USER_NAME, sysUser.getUserName());
        cookie2.setMaxAge(120);
        cookie2.setPath("/");
        ServletUtils.getResponse().addCookie(cookie);
        ServletUtils.getResponse().addCookie(cookie2);
        return R.ok();
    }

    /**
     * 重置密码
     */
    @Override
    public R<Integer> resetpass(String password) {

        if (StringUtil.isEmpty(password))
            throw new RuntimeException("密码必需填写");
        String token = "";
        String userName = "";
        for (Cookie c : ServletUtils.getRequest().getCookies()) {
            if (Objects.equals(CachePrefixConstants.COOKIE_KEY, c.getName()))
                token = c.getValue();
            if (Objects.equals(CachePrefixConstants.FORGET_USER_NAME, c.getName()))
                userName = c.getValue();
        }
        if (StringUtil.isAnyBlank(token, userName) || !singleUseTokenService.verifyToken(token))
            throw new RuntimeException("验证码已失效,请重新获取");
        SysUser sysUser = new SysUser();
        sysUser.setUserName(userName);
        sysUser.setPassword(password);
        return remoteSysUserService.resetpass(sysUser);
    }

    /**
     * 检查用户是否唯一
     */
    @Override
    public R<String> checkUserNameUnique(String userName) {
        return remoteSysUserService.checkUserNameUnique(userName);
    }

    /**
     * 获取公钥
     */
    @Override
    public R<?> getPublicKey(String username) throws Exception {
        if (StringUtil.isEmpty(username))
            throw new RuntimeException("用户名与密码必须填写");
        getLoginUser(username);// 验证下是否存在此用户
        return R.ok(keysService.createKeys(username));
    }

    /**
     * 发送邮箱验证码
     */
    @Override
    public R<?> getEmailCode(String emailValue, String eamilType) {
        if (Objects.equals(SysEmailSendTypeEnum.注册.getCode(), eamilType)) {
            if (StringUtil.isEmpty(emailValue))
                throw new RuntimeException("邮箱地址必需填写");
            if (!StringUtil.isEmail(emailValue))
                throw new RuntimeException("请填写正确的邮箱地址");
        }
        if (Objects.equals(SysEmailSendTypeEnum.忘记密码.getCode(), eamilType)) {
            verifyUserName(emailValue);
            SysUser sysUser = getLoginUser(emailValue).getSysUser();
            emailValue = sysUser.getEmail();
        }

        return emailTokenService.createKey(emailValue, eamilType);
    }

    /**
     * 校验用户名
     */
    private void verifyUserName(String emailValue) {
        if (StringUtil.isAnyBlank(emailValue))
            throw new RuntimeException("用户名必须填写");
        if (emailValue.length() < UserConstants.USERNAME_MIN_LENGTH || emailValue.length() > UserConstants.USERNAME_MAX_LENGTH)
            throw new RuntimeException("用户名不在指定范围");
    }

    /**
     * 获取用户
     */
    private LoginUser getLoginUser(String username) {
        R<LoginUser> userResult = remoteSysUserService.getUserByUserName(username);
        if (Objects.equals(R.FAIL, userResult.getCode()))
            throw new RuntimeException(userResult.getMsg());
        if (Objects.isNull(userResult) || Objects.isNull(userResult.getData()))
            throw new RuntimeException("用户名未注册");

        return userResult.getData();
    }

}
